/////// comments ////////////

#include <vector>
#include "combined.h"
#include "command.h"
#include "commandTable.h"
#include "definitions.h"
#include "log.h"
#include "stringutil.h"
#include "timestamp.h"
#include "world.h"

// Aedit Command definitions...
// (Keep in alphabetical order... it's MUCH easier)
aCmdCommands::aCmdCommands( void ) {
	setName( "commands" );
	setLevel( 1 );
	setEnabled( true );
	setOmniset( false );
}

bool aCmdCommands::execute( Character* character, const std::string& args ) {
	std::string buf;
	std::string temp;
	unsigned i=0;

	// HEAD Commands...
	if ( character->getLevel() >= HEAD ) {
		buf << "\n\r\t{cHead (level " << HEAD << ") commands:{x\n\r";
		for ( std::vector< Command* >::iterator it = aCommandTable::Instance().getCommands().begin(); it != aCommandTable::Instance().getCommands().end(); ++it ) {
			if ( (*it)->getLevel() == HEAD ) {
				if ( i % 6 == 0 ) {
					if ( i )
						buf << "\n\r";
					buf << "  ";
				}
				if ( (*it)->getEnabled() )
					buf << format( 12, (*it)->getName(), temp );
				else
					buf << format( 12, (*it)->getName(), temp, 'w' );
				i++;
			}
		}
	}

	// GOD Commands...
	if ( character->getLevel() >= GOD ) {
		i = 0;
		buf << "\n\r\t{cGod (level " << GOD << ") commands:{x\n\r";
		for ( std::vector< Command* >::iterator it = aCommandTable::Instance().getCommands().begin(); it != aCommandTable::Instance().getCommands().end(); ++it ) {
			if ( (*it)->getLevel() == GOD ) {
				if ( i % 6 == 0 ) {
					if ( i )
						buf << "\n\r";
					buf << "  ";
				}
				if ( (*it)->getEnabled() )
					buf << format( 12, (*it)->getName(), temp );
				else
					buf << format( 12, (*it)->getName(), temp, 'w' );
				i++;
			}
		}
	}

	// BUILDER Commands...
	if ( character->getLevel() >= BUILDER ) {
		i = 0;
		buf << "\n\r\t{cBuilder (level " << BUILDER << ") commands:{x\n\r";
		for ( std::vector< Command* >::iterator it = aCommandTable::Instance().getCommands().begin(); it != aCommandTable::Instance().getCommands().end(); ++it ) {
			if ( (*it)->getLevel() == BUILDER ) {
				if ( i % 6 == 0 ) {
					if ( i )
						buf << "\n\r";
					buf << "  ";
				}
				if ( (*it)->getEnabled() )
					buf << format( 12, (*it)->getName(), temp );
				else
					buf << format( 12, (*it)->getName(), temp, 'w' );
				i++;
			}
		}
	}

	// Regular Commands...
	buf << "\n\r\t{c-- Commands --{x \n\r";
	i = 0;
	for ( std::vector< Command* >::iterator it = aCommandTable::Instance().getCommands().begin(); it != aCommandTable::Instance().getCommands().end(); ++it ) {
		if ( (*it)->getLevel() == 1 ) {
			if ( i % 6 == 0 ) {
				if ( i )
					buf << "\n\r";
				buf << "  ";
			}
			if ( (*it)->getEnabled() )
				buf << format( 12, (*it)->getName(), temp );
			else
				buf << format( 12, (*it)->getName(), temp, 'w' );
			i++;
		}
	}

	character->Send( buf );

	return true;
}


aCmdExit::aCmdExit( void ) {
	setName( "exit" );
	setLevel( 1 );
	setEnabled( true );
	setOmniset( false );
	setTags( "exit aedit" );
	addSyntax( "syntax: exit     {Cleave aedit mode" );
}

bool aCmdExit::execute( Character* character, const std::string& args ) {

	character->setStatus( CONNECTED );
	character->Send( "You have left Aedit mode." );
	World::Instance().omninet( character->getName() + " has left aedit mode.", character );

	return true;
}

aCmdKeyword::aCmdKeyword( void ) {
	setName( "keyword" );
	setLevel( GOD );
	setEnabled( true );
	setOmniset( false );
	setTags( "keyword aedit" );
	addSyntax( "syntax: keyword <string>   {Cchanges the keyword of the current area to the given string" );
	addHelp( "String must contain no spaces." );
}

bool aCmdKeyword::execute( Character* character, const std::string& args ) {
	std::string keyword = lowerString( trim( args ) );

	if ( keyword.empty() ) {
		character->Send( getSyntax() );
		return false;
	}

	if ( character->getArea() == NULL ) {
		character->Send( "You haven't selected an area." );
		return false;
	}

	for ( std::map<std::string,Area*>::iterator it = World::Instance().getAreas().begin(); it != World::Instance().getAreas().end(); ++it ) {
		if ( keyword == lowerString( (*it).second->getKeyword() ) ) {
			character->Send( "There's already an area with that keyword." );
			return false;
		}
		if ( str_prefix( keyword, lowerString( (*it).second->getKeyword() ) ) ) {
			character->Send( "There's already an area with a keyword very similar to that." );
			return false;
		}
	}

	character->getArea()->setKeyword( keyword );
	character->Send( "Keyword changed to " + character->getArea()->getKeyword() + '.' );

	return true;
}

aCmdList::aCmdList( void ) {
	setName( "list" );
	setLevel( GOD );
	setEnabled( true );
	setOmniset( false );
	setTags( "list aedit" );
	addSyntax( "syntax: list     {Cshows data on all current areas" );
}

bool aCmdList::execute( Character* character, const std::string& args ) {
	std::string buf;
	std::map<std::string,Area*>::iterator a_it;

	character->Send( "\t{x--Area List--\n\r" );
	character->Send( "{Ykeyword                  {Cname{x\n\r" );
	character->Send( "   {RSize    {x[ {mRange         {x]   {Wpermissions{x\n\r" );
	character->Send( " {x-----------------------------------------------------\n\r" );
	for ( a_it = World::Instance().getAreas().begin(); a_it != World::Instance().getAreas().end(); ++a_it ) {
		buf.clear();
		character->Send( "{Y%-25s{x", (*a_it).second->getKeyword().c_str() );
		character->Send( "{C%-40s{x", (*a_it).second->getName().c_str() );
		character->Send( "\n\r   {R%-8d{x", (*a_it).second->getSize() );
		character->Send( "[ {m%-5d{x", (*a_it).second->getFirstv() );
		character->Send( " - {m%-5d{x ]", (*a_it).second->getLastv() );
		if ( (*a_it).second->getPermissions().size() == 0 )
			buf << "none";
		else
			for ( std::vector< std::string >::iterator i_it = (*a_it).second->getPermissions().begin(); i_it != (*a_it).second->getPermissions().end(); ++i_it )
				buf << ' ' << (*i_it);
		character->Send( "   {W%-20s{x", buf.c_str() );
		character->Send( "\n\r{x-----------------------------------------------------\n\r" );
	}

	return true;
}

aCmdMake::aCmdMake( void ) {
	setName( "make" );
	setLevel( GOD );
	setEnabled( true );
	setOmniset( true );
	setTags( "make aedit" );
	addSyntax( "syntax: make <keyword> <size>   {Ccreate a new area and select it" );
	addHelp( "<keyword> must contain no spaces" );
	addHelp( "<size> must be a multiple of 25" );
}

bool aCmdMake::execute( Character* character, const std::string& args ) {
	std::string keyword, s_start, s_size;
	unsigned u_size=0, next_vnum=0;
	Area* area = NULL;
	split( args, keyword, s_size );
	keyword = lowerString( trim( keyword ) );
	s_size = trim( s_size );

	if ( keyword.empty() || s_size.empty() ) {
		character->Send( getSyntax() );
		return false;
	}

	for ( std::map<std::string,Area*>::iterator it = World::Instance().getAreas().begin(); it != World::Instance().getAreas().end(); ++it ) {
		if ( keyword == lowerString( (*it).second->getKeyword() ) ) {
			character->Send( "There's already an area with that keyword." );
			return false;
		}
		if ( str_prefix( keyword, lowerString( (*it).second->getKeyword() ) ) ) {
			character->Send( "There's already an area with a keyword very similar to that." );
			return false;
		}
	}

	u_size = atoi( s_size.c_str() );
	if ( u_size % 25 ) {
		std::string message;
		message << "Area size must be a multiple of 25 and also be greater than " << START_VNUM << '.';
		character->Send( message );
		return false;
	}

	// Find the next available vnum...
	for ( std::map<std::string,Area*>::iterator it = World::Instance().getAreas().begin(); it != World::Instance().getAreas().end(); ++it )
		if ( (*it).second->getLastv() > next_vnum )
			next_vnum = (*it).second->getLastv()+1;

	area = new Area;
	area->setKeyword( keyword );
	area->setFirstv( next_vnum );
	area->setLastv( next_vnum+u_size-1 );
	area->setSize( u_size );
	World::Instance().add( area );
	character->setArea( area );
	character->Send( "Area " + area->getKeyword() + " created successfully." );
	return true;
}

aCmdName::aCmdName( void ) {
	setName( "name" );
	setLevel( GOD );
	setEnabled( true );
	setOmniset( false );
	setTags( "name aedit" );
	addSyntax( "syntax: name <string>   {Csets the name of the current area to the given string" );
}

bool aCmdName::execute( Character* character, const std::string& args ) {

	if ( args.empty() ) {
		character->Send( getSyntax() );
		return false;
	}

	if ( character->getArea() == NULL ) {
		character->Send( "You haven't selected an area." );
		return false;
	}

	character->getArea()->setName( args );
	character->Send( "Area name changed to \"" + args + "\"." );

	return true;
}

aCmdPermissions::aCmdPermissions( void ) {
	setName( "permissions" );
	setLevel( GOD );
	setEnabled( true );
	setOmniset( false );
	addSyntax( "syntax: permissions add <name>     {Cadd permissions for target to current area" );
	addSyntax( "        permissions remove <name>  {Cdrop permissions for target to current area" );
}

bool aCmdPermissions::execute( Character* character, const std::string& args ) {
	std::string buf, arg1, name;
	Area* area = NULL;
	Character* target = NULL;
	split( args, arg1, name );
	arg1 = trim( arg1 );
	name = trim( name );

	if ( arg1.empty() || name.empty() ) {
		character->Send( getSyntax() );
		return false;
	}

	if ( ( area = character->getArea() ) == NULL ) {
		character->Send( "You haven't selected an area." );
		return false;
	}

	if ( ( target = World::Instance().getCharacter( name ) ) == NULL ) {
		character->Send( "They can't be found." );
		return false;
	}

	if ( arg1 == "add" ) {
		if ( area->hasPermission( target ) ) {
			character->Send( "They've got permissions to that area already." );
			return false;
		}
		area->addPermission( target->getName() );
		character->Send( target->getName() + " has been given permissions to " + area->getKeyword() );
		target->Send( character->getName() + " has given you permission to " + area->getKeyword() );
		return true;
	}

	if ( arg1 == "drop" ) {
		if ( !area->hasPermission( target ) ) {
			character->Send( "They don't have permissions to that area." );
			return false;
		}
		area->dropPermission( target->getName() );
		character->Send( target->getName() + " has lost permissions to " + area->getKeyword() );
		target->Send( character->getName() + " has removed your permission to " + area->getKeyword() );
		return true;
	}

	return false;
}

aCmdRemove::aCmdRemove( void ) {
	setName( "remove" );
	setLevel( GOD );
	setEnabled( true );
	setOmniset( true );
	setTags( "remove aedit" );
	addSyntax( "syntax: remove <string>    {Cdeletes the first area matching the given string" );
	addHelp( "Any deleted areas are permanently removed." );
}

bool aCmdRemove::execute( Character* character, const std::string& args ) {
	Area* area = NULL;

	if ( ( area = character->getArea() ) == NULL ) {
		character->Send( "You haven't selected an area." );
		return false;
	}

	// check for chars in the area...
	for ( std::map<std::string,Character*>::iterator it = World::Instance().getCharacters().begin(); it != World::Instance().getCharacters().end(); ++it )
		if ( World::Instance().getParentArea( (*it).second->getRoom()->getVnum() ) == area ) {
			character->Send( "Don't be a jerk... there are players in that area!" );
			return false;
		}

	World::Instance().drop( area );
	character->Send( "Area " + area->getKeyword() + " deleted." );
	delete area;
	character->setArea( area = NULL );

	return true;
}

aCmdSelect::aCmdSelect( void ) {
	setName( "select" );
	setLevel( GOD );
	setEnabled( true );
	setOmniset( false );
	setTags( "select aedit" );
	addSyntax( "syntax: select <string>     {Cselect the area which matches the given string" );
}

bool aCmdSelect::execute( Character* character, const std::string& args ) {
	std::string keyword = trim( args );
	std::string buf;
	Area* area = NULL;

	if ( keyword.empty() ) {
		character->Send( getSyntax() );
		return false;
	}

	if ( ( area = World::Instance().getArea( keyword ) ) == NULL ) {
		character->Send( "Area not found." );
		return false;
	}

	if ( area->getLastv() < START_VNUM ) {
		character->Send( "You can't select that area." );
		return false;
	}

	if ( area->hasPermission( character ) ) {
		character->setArea( area );
		character->Send( "You've selected area " + character->getArea()->getName() + ')' );
		return true;
	} else {
		character->Send( "You don't have permission to that area." );
		return false;
	}

	character->Send( "That is not a valid area." );
	character->setArea( NULL );
	return false;
}

aCmdView::aCmdView( void ) {
	setName( "view" );
	setLevel( GOD );
	setEnabled( true );
	setOmniset( false );
	setTags( "view aedit" );
	addSyntax( "syntax: view      {Cview information about your current area" );
}

bool aCmdView::execute( Character* character, const std::string& args ) {
	std::string buf;
	Area* area = character->getArea();

	if ( area == NULL ) {
		character->Send( "You haven't selected an area." );
		return false;
	}

	buf << "--------------------------------------------------\n\r";
	buf << "Name:  {C" << area->getName() << "{x\n\r";
	buf << "Keyword: {c" << area->getKeyword() << "{x\n\r";
	buf << "Size:   {R" << area->getSize() << "{x\n\r";
	buf << "Range: {m" << area->getFirstv() << " {x- {m" << area->getLastv() << "{x\n\r";
	buf << "--------------------------------------------------";

	character->Send( buf );
	return true;
}
